/*
 * de puzzelklasse, woei!
 *
 * eigenlijk de hoofdklasse van ons programma, genereert puzzels, houdt de goalpuzzel bij etc.
 */

package schuifpuzzelen;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 *
 * @author Laurens van Dijk, s3012557
 */
public class Puzzle implements Node{

    public int[][] puzzelArray;
    public int hole_x, hole_y, BOARDHEIGHT=3, BOARDWIDTH=3;

    
    /**
     * Lijsten opnieuw initialiseren en een nieuwe puzzel genereren. Wederom een flexibele functie,
     * die ook goed omgaat met grotere puzzels en in theorie ook opnieuw gebruikt kan worden door het programma.
     */
    public void puzzelVerzinnen()
    {
        Main.alGehad = new ArrayList();
        Main.alGehad.add(0);
        puzzelArray = new int[BOARDHEIGHT][BOARDWIDTH];

        int a = (BOARDHEIGHT*BOARDWIDTH)-1, temp = 0, z = 0, i = 0;
        Random generator = new Random();

        for(i=0; i<BOARDHEIGHT; i++)
        {           
            for(z=0; z<BOARDWIDTH; z++)
               {
                if(i < BOARDHEIGHT-1 || z < BOARDWIDTH-1) {
                while (Main.alGehad.contains(temp)) {
                temp = generator.nextInt(a+1);
                }//zolang het getalletje niet uniek is blijven prutsen. - L

                Main.alGehad.add(temp); //nieuw uniek getalletje wel toevoegen aan de list met al gebruikte getallen :+ - L
                puzzelArray[i][z] = temp;  //uniek getal toevoegen aan het bord. - L
                }
            }
        }

        hole_x = BOARDWIDTH;
        hole_y = BOARDHEIGHT;
    }
    
    /**
     * Simpele functie om de puzzel netjes te tonen. De functie is zo flexibel mogelijk, om ook om te kunnen gaan met
     * grotere puzzels. Verder toont deze functie ook netjes waar zich het 'gat' in de puzzel bevindt.
     */
    public void puzzelTonen(int[][] puzzel)
    {
        String tmpStr = "";
        for(int i=0; i<BOARDHEIGHT; i++)
        {
            for(int z=0; z<BOARDWIDTH; z++)
            {
                if(puzzel[i][z] == 0) { //want 0 is waar zich het 'gat' in de puzzel bevindt.
                    tmpStr = tmpStr + (" + "+Main.holeChar); }
                else
                    tmpStr = tmpStr + (" + "+puzzel[i][z]);
            }
            tmpStr = tmpStr + '\n';
        }
        System.out.print(tmpStr);
    }

    /**
     * deze functie loopt door de puzzelArray heen, om te zien of deze gelijk is aan de goalPuzzel.
     * @return wel of niet gelijk aan de goalPuzzel
     */
    public boolean isGoal()
    {
        if(Arrays.equals(puzzelArray, Main.goalPuzzel))
                    return true;
        return false;
    }

    /**
     * staat in de opdracht dat dit moet, not sure why..
     *
     * @param puz1 puzzeltje
     * @param puz2 nog een puzzeltje
     * @return false als puz1 != puz2, anders true.
     */
    public boolean equals(int[][] puz1, int[][] puz2)
    {
        if(Arrays.equals(puz1, puz2))
            return true;
        return false;
    }

    public Puzzle noord() {
        Puzzle p = new Puzzle(this);
        if (p.hole_y > 0) {
            int mov = p.puzzelArray[hole_y-1][hole_x];
            p.puzzelArray[hole_y-1][hole_x] = p.puzzelArray[hole_y][hole_x];
            p.puzzelArray[hole_y][hole_x] = mov;
            p.hole_y--;
        }
        return p;
    }

    public Puzzle oost() {
        Puzzle p = new Puzzle(this);
        if (p.hole_x < BOARDWIDTH) {
            int mov = p.puzzelArray[hole_y][hole_x+1];
            p.puzzelArray[hole_y][hole_x+1] = p.puzzelArray[hole_y][hole_x];
            p.puzzelArray[hole_y][hole_x] = mov;
            p.hole_x++;
        }
        return p;
    }

    public Puzzle zuid() {
        Puzzle p = new Puzzle(this);
        if (p.hole_y < BOARDHEIGHT) {
            int mov = p.puzzelArray[hole_y+1][hole_x];
            p.puzzelArray[hole_y+1][hole_x] = p.puzzelArray[hole_y][hole_x];
            p.puzzelArray[hole_y][hole_x] = mov;
            p.hole_y++;
        }
        return p;
    }

    public Puzzle west() {
        Puzzle p = new Puzzle(this);
        if (p.hole_x > 0) {
            int mov = p.puzzelArray[hole_y][hole_x-1];
            p.puzzelArray[hole_y][hole_x-1] = p.puzzelArray[hole_y][hole_x];
            p.puzzelArray[hole_y][hole_x] = mov;
            p.hole_x--;
        }
        return p;
    }

    
    public List successors()
    {
        List l = new ArrayList();
        if (hole_x == 0 && hole_y == 0) {
            l.add(oost());
            l.add(zuid());
        } else if (hole_x > 0 && hole_y == 0) {
            l.add(oost());
            l.add(west());
            l.add(zuid());
        } else if (hole_x > 0 && hole_y > 0) {
            l.add(noord());
            l.add(oost());
            l.add(zuid());
            l.add(west());
        } else if (hole_x == 0 && hole_y > 0) {
            l.add(noord());
            l.add(zuid());
            l.add(oost());
        } else if (hole_x == BOARDWIDTH && hole_y == BOARDHEIGHT) {
            l.add(noord());
            l.add(oost());
        }

        return l;
     /*   if(puzzelArray[0][0] == 0 || puzzelArray[0][BOARDWIDTH-1] == 0 || puzzelArray[BOARDHEIGHT-1][0] == 0 || puzzelArray[BOARDHEIGHT-1][BOARDWIDTH-1] == 0) {
            System.out.println("OHNOES EEN HOEKJE!!one! en wel op: "+hole_x+", "+hole_y);
        }*/
    }

    /**
     * constructor, genereert een nieuwe puzzel om op te lossen en toont deze.
     */
    public Puzzle() //no u. constructor dus. - L
    {
        puzzelVerzinnen(); //3x3 bord, arbitary value, lekker laten voorlopig. - L
        puzzelTonen(puzzelArray); //mehprintseldebugiets - L
    }

    public Puzzle(Puzzle _p) {
        puzzelArray = _p.puzzelArray;
        hole_x = _p.hole_x;
        hole_y = _p.hole_y;
    }

    public Node predecessor() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}